////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include "BaseObjectHandler.hpp"

#include <SmegCore/Entity/PlaceableObject.hpp>

#include "../tinyxml2/tinyxml2.h"
#include "../Canvas/SmegEditorCanvas.hpp"

////////////////////////////////////////////////////////////
/// Construct the BaseObjectHandler
////////////////////////////////////////////////////////////
BaseObjectHandler::BaseObjectHandler() :
    BaseXMLObject(),
    m_iIconId( -1 ),
    m_pCanvas( NULL ),
    m_pObject( NULL )
{
}

////////////////////////////////////////////////////////////
/// Copy Constructor of the BaseObjectHandler
////////////////////////////////////////////////////////////
BaseObjectHandler::BaseObjectHandler( const BaseObjectHandler& _Copy ) :
    BaseXMLObject( _Copy ),
    m_iIconId( _Copy.m_iIconId ),
    m_pCanvas( _Copy.m_pCanvas ),
    m_pObject( NULL )
{
    if ( _Copy.m_pObject ) {
        m_pObject = _Copy.m_pObject->Clone();
    }
}

////////////////////////////////////////////////////////////
/// Init the handler from the properties
/// BaseObjectHandler::Init need to be called AFTER the specialized class
////////////////////////////////////////////////////////////
bool BaseObjectHandler::InitFromGrid( wxPropertyGrid* _pPropertyGrid ) {
    // Angle
    wxPGProperty* pCurProp = _pPropertyGrid->GetProperty("Angle");
    wxAny angleValue = pCurProp->GetValue();
    m_pObject->SetAngleDeg( angleValue.As<float>() );

    return true;
}
    
////////////////////////////////////////////////////////////
/// Init the handler from an XMLElement
/// BaseObjectHandler::Init need to be called AFTER the specialized class
////////////////////////////////////////////////////////////
bool BaseObjectHandler::InitFromXML( tinyxml2::XMLElement* _pElement, const wxString& _ProjectPath ) {
    // Id
    m_ID = _pElement->Attribute( "id" );

    // Get the infos
    tinyxml2::XMLElement* pParamElem = _pElement->FirstChildElement( "Param" );
    while ( pParamElem ) {
        wxString paramName = pParamElem->Attribute( "name" );
        if ( "Center" == paramName ) {
            // Position
            m_pObject->SetCenter( sf::Vector2f( pParamElem->FloatAttribute( "x" ), pParamElem->FloatAttribute( "y" ) ) );
        } else if ( "Angle" == paramName ) {
            // Angle
            m_pObject->SetAngleDeg( pParamElem->FloatAttribute( "value" ) );
        }

        pParamElem = pParamElem->NextSiblingElement( "Param" );
    }

    return true;
}

////////////////////////////////////////////////////////////
/// Init the handler from the properties
/// BaseObjectHandler::Init need to be called AFTER the specialized class
////////////////////////////////////////////////////////////
bool BaseObjectHandler::Init( SmegEditorCanvas* _pCanvas, wxPropertyGrid* _pPropertyGrid, const sf::Vector2f& _Position, int _iIconId ) {
    m_pCanvas = _pCanvas;
    if ( -1 != _iIconId ) {
        m_iIconId = _iIconId;
    }

    if ( !InitFromGrid( _pPropertyGrid ) ) {
        return false;
    }

    // Position
    m_pObject->SetCenter( _Position );
    wxPGProperty* pCurProp = _pPropertyGrid->GetProperty("Center");
    pCurProp->GetPropertyByName("x")->SetValueFromString( wxString::Format("%f", _Position.x) );
    pCurProp->GetPropertyByName("y")->SetValueFromString( wxString::Format("%f", _Position.y) );

    m_pCanvas->SetSelectedObject( m_pObject );

    return true;
}
    
////////////////////////////////////////////////////////////
/// Init the handler from an XMLElement
/// BaseObjectHandler::Init need to be called AFTER the specialized class
////////////////////////////////////////////////////////////
bool BaseObjectHandler::Init( SmegEditorCanvas* _pCanvas, tinyxml2::XMLElement* _pElement, const wxString& _ProjectPath, int _iIconId ) {
    m_pCanvas = _pCanvas;
    if ( -1 != _iIconId ) {
        m_iIconId = _iIconId;
    }

    return InitFromXML( _pElement, _ProjectPath );
}
    
////////////////////////////////////////////////////////////
/// Return the value of a property
////////////////////////////////////////////////////////////
wxString BaseObjectHandler::GetValueAsString( const wxString& _PropertyName ) const {
    if ( "Center.x" == _PropertyName ) {
        return wxString::Format( "%f", m_pObject->GetCenter().x );
    } else if ( "Center.y" == _PropertyName ) {
        return wxString::Format( "%f", m_pObject->GetCenter().y );
    } else if ( "Angle" == _PropertyName ) {
        return wxString::Format( "%f", m_pObject->GetAngleDeg() );
    } else {
        return wxEmptyString;
    }
}
    
////////////////////////////////////////////////////////////
/// Handle the change of a property and apply it to the object
////////////////////////////////////////////////////////////
bool BaseObjectHandler::OnPropertyChanged( wxPropertyGrid* _pPropertyGrid, wxPGProperty* _pChangedProperty ) {
    // GetValue() returns wxVariant, but it is converted transparently to
    // wxAny
    wxAny value = _pChangedProperty->GetValue();
    // Also, handle the case where property value is unspecified
    if ( value.IsNull() )
        return true;

    // Handle changes in values, as needed
    const wxString& propName( _pChangedProperty->GetName() );
    if ( "Center" == propName || "Center" == propName.BeforeFirst( '.' ) ) {
        _pChangedProperty = _pPropertyGrid->GetProperty( "Center" );
        sf::Vector2f newCenter = sf::Vector2f(
            _pChangedProperty->GetPropertyByName("x")->GetValue().GetAny().As<float>(),
            _pChangedProperty->GetPropertyByName("y")->GetValue().GetAny().As<float>()
            );

        m_pCanvas->OnObjectMove( newCenter - m_pObject->GetCenter() );
    } else if ( "Angle" == propName ) {
        float newAngle = _pChangedProperty->GetValue().GetAny().As<float>();
        m_pCanvas->OnObjectRotate( newAngle - m_pObject->GetAngleDeg() );

        _pChangedProperty->SetValueFromString( wxString::Format("%f", m_pObject->GetAngleDeg() ) );
    } else {
        return false;
    }

    return true;
}
    
////////////////////////////////////////////////////////////
/// Create an XML string with the value of the object
////////////////////////////////////////////////////////////
wxString BaseObjectHandler::InnerXMLString( const wxString& _ProjectPath, const wxString& _Tab ) const {
    const sf::Vector2f& center( m_pObject->GetCenter() );

    return _Tab + wxT( "<Param name=\"Center\" x=\"" ) + wxString::Format( "%f", center.x ) + wxT( "\" " ) +
                                            wxT( "y=\"" ) + wxString::Format( "%f", center.y ) + wxT( "\" />\n" ) +
        _Tab + wxT( "<Param name=\"Angle\" value=\"" ) + wxString::Format( "%f", m_pObject->GetAngleDeg() ) + wxT( "\" />\n" );
}